﻿using System;
using System.Drawing;
using System.Windows.Forms;
using Blader.ActionHandler;
using Blader.Cache;
using Blader.Config;
using Blader.UI.TextBox;
using Blader.UI.Win32;

namespace Blader.UI.Forms
{
    public partial class SearchForm1 : Form
    {
        #region EntryMode enum

        public enum EntryMode
        {
            Text,
            List
        }

        #endregion

        private readonly HandlerContext handlerContext;
        private EntryMode entryMode = EntryMode.Text;
        private AutoCompleteEntryCollection suggestionItems;
        private AutoCompleteTriggerCollection triggers;

        public SearchForm1(HandlerContext handlerContext)
        {
            this.handlerContext = handlerContext;
            InitializeComponent();
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WMMessages.WM_NCHITTEST && m.Result.ToInt32() == WMMessages.HTCLIENT)
            {
                m.Result = new IntPtr(WMMessages.HTCAPTION);
            }
        }

        private void SearchForm1_Load(object sender, EventArgs e)
        {
            InitSuggestion();
            InitLocation();
            InitTrigger();
        }

        private void InitTrigger()
        {
            triggers = new AutoCompleteTriggerCollection();
            triggers.Add(new TextLengthTrigger(2));
            triggers.Add(new ShortCutTrigger(Keys.Enter, TriggerState.SelectAndConsume));
            triggers.Add(new ShortCutTrigger(Keys.Tab, TriggerState.Select));
            triggers.Add(new ShortCutTrigger(Keys.Control | Keys.Space, TriggerState.ShowAndConsume));
            triggers.Add(new ShortCutTrigger(Keys.Escape, TriggerState.HideAndConsume));
        }

        private void InitSuggestion()
        {
            CacheService cacheService = CacheService.GetCacheService();

            if (handlerContext.IsInVs)
            {
                if (!string.IsNullOrEmpty(handlerContext.ApplicationObject.Solution.FileName))
                {
                    AutoCompleteEntryCollection files =
                        cacheService.LoadSolutionSqlFiles(handlerContext.ApplicationObject.Solution.FileName);
                    suggestionItems = files;
                }
            }
            else
            {
                AutoCompleteEntryCollection files = cacheService.LoadProjectSqlFiles();
                suggestionItems = files;
            }
        }

        private void InitLocation()
        {
            int x;
            int.TryParse(IniFile.Instance.IniReadValue("SearchForm", "Pos-X"), out x);
            int y;
            int.TryParse(IniFile.Instance.IniReadValue("SearchForm", "Pos-Y"), out y);
            Location = new Point(x, y);
        }

        private void SearchForm1_FormClosed(object sender, FormClosedEventArgs e)
        {
            IniFile.Instance.IniWriteValue("SearchForm", "Pos-X", Location.X.ToString());
            IniFile.Instance.IniWriteValue("SearchForm", "Pos-Y", Location.Y.ToString());
        }

        protected virtual bool DefaultCmdKey(ref Message msg, Keys keyData)
        {
            bool val = base.ProcessCmdKey(ref msg, keyData);


            switch (triggers.OnCommandKey(keyData))
            {
                case TriggerState.ShowAndConsume:
                    {
                        val = true;
                        ShowList();
                    }
                    break;
                case TriggerState.Show:
                    {
                        ShowList();
                    }
                    break;
                case TriggerState.HideAndConsume:
                    {
                        val = true;
                        HideList();
                    }
                    break;
                case TriggerState.Hide:
                    {
                        HideList();
                    }
                    break;
                case TriggerState.SelectAndConsume:
                    {
                        if (entryMode == EntryMode.List)
                        {
                            val = true;
                            SelectAutoCompleteEntryItem();
                        }
                    }
                    break;
                case TriggerState.Select:
                    {
                        if (entryMode == EntryMode.List)
                        {
                            SelectAutoCompleteEntryItem();
                        }
                    }
                    break;
                default:
                    break;
            }


            return val;
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Up:
                    {
                        entryMode = EntryMode.List;
                        if (SuggestionListBox.SelectedIndex > 0)
                        {
                            SuggestionListBox.SelectedIndex--;
                        }
                        return true;
                    }
                case Keys.Down:
                    {
                        entryMode = EntryMode.List;
                        if (SuggestionListBox.SelectedIndex < SuggestionListBox.Items.Count - 1)
                        {
                            SuggestionListBox.SelectedIndex++;
                        }
                        return true;
                    }
                default:
                    {
                        return DefaultCmdKey(ref msg, keyData);
                    }
            }
        }

        private void SearchTextBox_TextChanged(object sender, EventArgs e)
        {
            switch (triggers.OnTextChanged(SearchTextBox.Text))
            {
                case TriggerState.Show:
                    {
                        ShowList();
                    }
                    break;
                case TriggerState.Hide:
                    {
                        HideList();
                    }
                    break;
                default:
                    {
                        UpdateList();
                    }
                    break;
            }
        }

        protected virtual void ShowList()
        {
            if (entryMode == EntryMode.Text)
            {
                SuggestionListBox.SelectedIndex = -1;

                UpdateList();
            }
            else
            {
                UpdateList();
            }
        }

        protected virtual void HideList()
        {
            entryMode = EntryMode.Text;
        }

        protected virtual void UpdateList()
        {
            object selectedItem = SuggestionListBox.SelectedItem;

            SuggestionListBox.Items.Clear();
            SuggestionListBox.Items.AddRange(suggestionItems.Filter(SearchTextBox.Text).ToArray());

            if (selectedItem != null && SuggestionListBox.Items.Contains(selectedItem))
            {
                EntryMode oldMode = entryMode;
                entryMode = EntryMode.List;
                SuggestionListBox.SelectedItem = selectedItem;
                entryMode = oldMode;
            }

            if (SuggestionListBox.Items.Count == 0)
            {
                HideList();
            }
            else
            {
                int visItems = SuggestionListBox.Items.Count;
                if (visItems > 8)
                    visItems = 8;

                Height = panel1.Height + (visItems * SuggestionListBox.ItemHeight) + 2;
            }

            if (SuggestionListBox.Items.Count > 0 && SuggestionListBox.SelectedIndex == -1)
            {
                EntryMode oldMode = entryMode;
                entryMode = EntryMode.List;
                SuggestionListBox.SelectedIndex = 0;
                entryMode = oldMode;
            }
        }

        protected virtual void SelectAutoCompleteEntryItem()
        {
            if (SuggestionListBox.SelectedIndex == -1)
            {
                return;
            }

            IAutoCompleteEntry autoCompleteEntry = (IAutoCompleteEntry)SuggestionListBox.SelectedItem;
            SearchTextBox.Text = autoCompleteEntry.DisplayName;

            if (Text.Length > 0)
            {
                SearchTextBox.SelectionStart = Text.Length;
            }

            HideList();

            Native.ShellExecute(IntPtr.Zero, "open", autoCompleteEntry.Value, null, null, 3);
        }

        private void List_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (entryMode != EntryMode.List)
            {
                SelectAutoCompleteEntryItem();
            }
        }

        private void List_MouseDown(object sender, MouseEventArgs e)
        {
            for (int i = 0; i < SuggestionListBox.Items.Count; i++)
            {
                if (SuggestionListBox.GetItemRectangle(i).Contains(e.X, e.Y))
                {
                    SuggestionListBox.SelectedIndex = i;
                    SelectAutoCompleteEntryItem();
                }
            }
            HideList();
        }

        private void List_DrawItem(object sender, DrawItemEventArgs e)
        {
            Color bColor = e.BackColor;
            if (e.State == DrawItemState.Selected || e.State == DrawItemState.HotLight)
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.DeepSkyBlue), e.Bounds);
                e.Graphics.DrawString(SuggestionListBox.Items[e.Index].ToString(), e.Font,
                                      new SolidBrush(Color.DeepSkyBlue), e.Bounds, StringFormat.GenericDefault);
            }
            else
            {
                e.DrawBackground();
                e.Graphics.DrawString(SuggestionListBox.Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor),
                                      e.Bounds, StringFormat.GenericDefault);
            }
        }
    }
}